<!doctype html>
<html class="theme-next use-motion theme-next-mist">
<head>
  
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

  <meta name="google-site-verification" content="K8DCBviaoTBKVs28YBB7IBIbospQ9RVlgSh81RYMUhY" />


  <meta name="baidu-site-verification" content="tXr3ZTm3Hx" />



  <link rel="stylesheet" type="text/css" href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5"/>


<link rel="stylesheet" type="text/css" href="/css/main.css?v=0.4.5.1"/>

  <meta name="description" content="xgfe's blog. 鲜果前端的技术博客，鲜果前端研发部官方博客。前端基础技术研究：html, html5, javascript, css, css3；前端框架研究：angularJs, react, react native." />


  <meta name="keywords" content="React Native,ReactART," />


  <link rel="alternate" target="_blank" href="/atom.xml" title="xgfe" type="application/atom+xml" />


  <link rel="shorticon icon" type="image/x-icon" href="http://p0.meituan.net/xgfe/2db359f56ce13be30dedef160e0e57ce16958.ico?v=0.4.5.1" />

<meta name="description" content="React Native ART 由来react-art是reactjs团队基于art（一个兼容各个浏览器SVG绘制的API封装）开发的模块，让react开发者能使用jsx语法绘制svg. react native团队分别在0.10.0和0.18.0也添加了iOS和Android平台对react-art的支持，RN在本文写稿时已经发版至0.41.0，官网文档至今对其只字未提。本文旨在介绍安静躺在r">
<meta name="keywords" content="React Native,ReactART">
<meta property="og:type" content="article">
<meta property="og:title" content="React Native ART介绍">
<meta property="og:url" content="http://xgfe.github.io/2017/02/07/TinySymphony/React-Native-ART介绍/index.html">
<meta property="og:site_name" content="xgfe">
<meta property="og:description" content="React Native ART 由来react-art是reactjs团队基于art（一个兼容各个浏览器SVG绘制的API封装）开发的模块，让react开发者能使用jsx语法绘制svg. react native团队分别在0.10.0和0.18.0也添加了iOS和Android平台对react-art的支持，RN在本文写稿时已经发版至0.41.0，官网文档至今对其只字未提。本文旨在介绍安静躺在r">
<meta property="og:image" content="http://7xjgb0.com1.z0.glb.clouddn.com/artAnimationStars.gif">
<meta property="og:updated_time" content="2017-04-12T08:03:36.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="React Native ART介绍">
<meta name="twitter:description" content="React Native ART 由来react-art是reactjs团队基于art（一个兼容各个浏览器SVG绘制的API封装）开发的模块，让react开发者能使用jsx语法绘制svg. react native团队分别在0.10.0和0.18.0也添加了iOS和Android平台对react-art的支持，RN在本文写稿时已经发版至0.41.0，官网文档至今对其只字未提。本文旨在介绍安静躺在r">
<meta name="twitter:image" content="http://7xjgb0.com1.z0.glb.clouddn.com/artAnimationStars.gif">


<script type="text/javascript" id="hexo.configuration">
  var CONFIG = {
    scheme: 'Mist',
    sidebar: 'post'
  };
</script>

  <title> React Native ART介绍 | xgfe </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
  <div style="position: fixed; top: -9999px; left: -9999px;">
    <img src="http://p0.meituan.net/xgfe/082a9624ba5ae8602150a2d43968463e49348.png" alt="xgfe"/>
  </div>
  <!--[if lte IE 8]>
  <div style=' clear: both; height: 59px; padding:0 0 0 15px; position: relative;margin:0 auto;'>
    <a href="http://windows.microsoft.com/en-US/internet-explorer/products/ie/home?ocid=ie6_countdown_bannercode">
      <img src="http://7u2nvr.com1.z0.glb.clouddn.com/picouterie.jpg" border="0" height="42" width="820"
           alt="You are using an outdated browser. For a faster, safer browsing experience, upgrade for free today or use other browser ,like chrome firefox safari."
           style='margin-left:auto;margin-right:auto;display: block;'/>
    </a>
  </div>
<![endif]-->
  

  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?3601d4483819a5ab6ddabb0b6422a328";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>



  <div class="container one-column page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><h1 class="site-meta">
  <span class="logo-line-before"><i></i></span>
  <a href="/" class="brand" rel="start">
      <span class="logo">
        <i class="icon-next-logo"></i>
      </span>
      <span class="site-title">xgfe</span>
  </a>
  <span class="logo-line-after"><i></i></span>
</h1>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  
  

  
    <ul id="menu" class="menu menu-left">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            <i class="menu-item-icon icon-next-home"></i> <br />
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            <i class="menu-item-icon icon-next-archives"></i> <br />
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            <i class="menu-item-icon icon-next-tags"></i> <br />
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-join">
          <a href="/join" rel="section">
            <i class="menu-item-icon icon-next-join"></i> <br />
            加入我们
          </a>
        </li>
      
      <!-- slide-links added by felix -->
      <li class="menu-item menu-item-slides" style="opacity: 1; transform: translateY(0px);">
        <a href="http://xgfe.github.io/Basics/" target="_blank" rel="section">
          <i class="menu-item-icon icon-next-slides"></i> <br>
          Basics
        </a>
      </li>
      <li class="menu-item menu-item-slides" style="opacity: 1; transform: translateY(0px);">
        <a href="https://slides.com/xgfe" target="_blank" rel="section">
          <i class="menu-item-icon icon-next-slides"></i> <br>
          Slides
        </a>
      </li>

      
      
    </ul>
  

  
    <div class="site-search">
      

    </div>
  

    <div class="site-search">
      <form class="site-search-form" id="gg-form" action="https://www.google.com/webhp" >
        <input type="text" name="q" id="gg-search-input" class="menu-search-input">
      </form>
    </div>
</nav>
 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div id="content" class="content"> 

  <div id="posts" class="posts-expand">
    

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <header class="post-header">

      
      
        <h1 class="post-title" itemprop="name headline">
          
          
            
              React Native ART介绍
            
          
        </h1>
      

      <div class="post-meta">
        <span class="post-time">
          发表于
          <time itemprop="dateCreated" datetime="2017-02-07T17:33:09+08:00" content="2017-02-07">
            2017-02-07
          </time>
        </span>

        
          <span class="post-category" >
            &nbsp; | &nbsp; 作者
            
              <span itemprop="about" itemscope itemtype="https://schema.org/Thing">
                <a href="/categories/TinySymphony/" itemprop="url" rel="index">
                  <span itemprop="name">TinySymphony</span>
                </a>
              </span>

              
              

            
          </span>
        

        
          
        

        <!-- tags 挪动位置 -->
        
          <span class="post-tags">
            &nbsp; | &nbsp;
            
              <a href="/tags/React-Native/" rel="tag"><i class="icon-next-tags"></i>React Native</a>
            
              <a href="/tags/ReactART/" rel="tag"><i class="icon-next-tags"></i>ReactART</a>
            
          </span>
        
      </div>
    </header>

    <div class="post-body">

      
      

      
        <span itemprop="articleBody"><h3 id="React-Native-ART-由来"><a href="#React-Native-ART-由来" class="headerlink" title="React Native ART 由来"></a>React Native ART 由来</h3><p><code>react-art</code>是reactjs团队基于<code>art</code>（一个兼容各个浏览器SVG绘制的API封装）开发的模块，让react开发者能使用jsx语法绘制svg.</p>
<p>react native团队分别在0.10.0和0.18.0也添加了iOS和Android平台对react-art的支持，RN在本文写稿时已经发版至<code>0.41.0</code>，官网文档至今对其只字未提。本文旨在介绍安静躺在<code>react-native/Libraries/</code>里的<code>ART</code>，并展示一些实践结果。</p>
<a id="more"></a>
<h3 id="ART能干什么"><a href="#ART能干什么" class="headerlink" title="ART能干什么"></a>ART能干什么</h3><p>俗话说，<strong>库如其名</strong>，背负着如此具有“艺术感”名字的ART生来就是为了绘制矢量图的，或者说是“画”UI的。</p>
<p>在web页面开发时想必大部分前端工程师都使用过svg格式的切图，矢量保证了图片的高清无码而且较小的文件体积对页面加载速度十分友好。并且svg绘图的另一个极大优点是其自身在dom树中能绑定事件，为数据可视化领域所青睐。</p>
<p>React Native开发者是无法直接使用矢量图的，<code>&lt;Image&gt;</code>标签不支持svg格式的资源。目前使用矢量图标的一个选择是<a href="https://github.com/oblador/react-native-vector-icons" target="_blank" rel="external">react-native-vector-icons</a>这种icon font形式的实现。</p>
<p>另一条路就是ART。ART相比于<code>&lt;Image&gt;</code>标签的最大优势是同步渲染，<code>&lt;Image&gt;</code>标签在官网文档的描述中有这样一句：</p>
<blockquote>
<p>Image decoding can take more than a frame-worth of time</p>
</blockquote>
<p>图片的解码由于不在主线程中进行，所以不能确保所有图片和内容在同一帧内出现。使用<code>&lt;Image&gt;</code>标签的制作的组件这就很尴尬了，整个组件里的图（比如icon）可能是三三两两“闪现”出来的，让人怀疑是个<code>webview</code>，体验远不如原生。</p>
<p>此外ART和icon-font一样，让开发者摆脱了针对<code>&lt;Image&gt;</code>提供<code>@2x</code>/<code>@3x</code>图的麻烦。</p>
<h3 id="上手ART"><a href="#上手ART" class="headerlink" title="上手ART"></a>上手ART</h3><blockquote>
<p>注：本文所用RN版本<code>0.40.0</code></p>
</blockquote>
<h4 id="事先准备"><a href="#事先准备" class="headerlink" title="事先准备"></a>事先准备</h4><ol>
<li>ART在iOS上使用需要事先导入ART的链接库，找到<code>node_modules/react-native/Libraries/ART/ART.xcdoeproj</code>拖入Xcode对应项目的<code>Libraries</code></li>
<li>打开<code>General Settings</code>添加<code>libART.a</code>到<code>Linked Frameworks and Libraries</code>列表</li>
<li><code>cmd+b</code>重新构建项目</li>
</ol>
<h4 id="基本API"><a href="#基本API" class="headerlink" title="基本API"></a>基本API</h4><blockquote>
<p><a href="https://github.com/react-native-china/react-native-ART-doc/blob/master/doc.md" target="_blank" rel="external">ART文档 (非官方)</a> 在github上有这样比较全一篇文档，可以选择直接看它了解使用。</p>
</blockquote>
<p>ART目前只提供以下几个API（打印属性窥视到的…）：</p>
<p>前四个属性是以<code>ReactComponent</code>为原型的对象，可推断是作为jsx标签使用的。</p>
<ul>
<li><code>Surface</code>标签对应svg中的<code>svg</code>标签，所有ART的jsx内容需要被其包含</li>
<li><code>Group</code>标签对应<code>g</code>标签</li>
<li><code>Shape</code>标签对应<code>path</code>标签</li>
<li><code>Text</code>标签对应<code>text</code>标签</li>
<li><code>Transform</code>做图形变换的API</li>
<li><code>Path</code>绘制路径API</li>
<li><code>LinearGradient</code>创建线性渐变API</li>
<li><code>RadialGradient</code>创建径向渐变API</li>
<li><code>Pattern</code>疑似<code>pattern</code>标签做图片填充的API，使用标准格式推测为<code>new Pattern(url, width, height, left, top)</code></li>
<li><code>ClippingRectangle</code>意义不明，可能和<code>clipPath</code>接近，定义一个蒙版</li>
</ul>
<p>可以看到ART和svg还是有不同的，有点像是阉割后的svg，没有诸如<code>path</code>/<code>rect</code>/<code>animate</code>/<code>circle</code>/<code>ellipse</code>的标签。</p>
<p>当然已经有开发者做了实现，可以方便地使用svg标签写ART =&gt; <a href="https://github.com/react-native-community/react-native-svg" target="_blank" rel="external">react-native-svg</a></p>
<p>不过本文后续的例子还是使用原原本本的ART实践。</p>
<h4 id="ART基础使用栗子"><a href="#ART基础使用栗子" class="headerlink" title="ART基础使用栗子"></a>ART基础使用栗子</h4><p>基本的几个案例如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 后面例子的引入会省略</span></div><div class="line"><span class="keyword">import</span> &#123;ART&#125; <span class="keyword">from</span> <span class="string">'react-native'</span>;</div><div class="line"><span class="keyword">const</span> &#123;</div><div class="line">  Surface,</div><div class="line">  Group,</div><div class="line">  Shape,</div><div class="line">  Path,</div><div class="line">  Transform</div><div class="line">&#125; = ART;</div><div class="line"></div><div class="line"><span class="comment">// 绘制ART图像</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">drawVector</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> (</div><div class="line">    &lt;Surface width=&#123;300&#125; height=&#123;400&#125;&gt;</div><div class="line">      &lt;Group x=&#123;0&#125; y=&#123;0&#125;&gt;</div><div class="line">        &lt;Shape</div><div class="line">          scale=&#123;1.0&#125;</div><div class="line">          stroke=&#123;"#ff0"&#125;</div><div class="line">          strokeWidth=&#123;4&#125;</div><div class="line">          d=&#123;generateSvgPath()&#125;</div><div class="line">          transform=&#123;new Transform().translate(150, 150).rotate(30, 100, 100).scale(3, 2)&#125;</div><div class="line">        /&gt;</div><div class="line">      &lt;/Group&gt;</div><div class="line">    &lt;/Surface&gt;</div><div class="line">  );</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>Surface</code>必须是ART内容的父层，并且其中不能包含非ART标签（否则直接闪退…），需要指定宽高。</p>
<p><code>Group</code>可有可无，当绘制内容较多时可以用其统一管理，可以把它当做<code>View</code>标签使用，可制定内容在画布绘制的起点。</p>
<p><code>Shape</code>是目前ART绘制的一把手，<code>d</code>属性对标svg的<code>path</code>标签上的<code>d</code>属性。</p>
<p>所有的ART标签都可以使用<code>transform</code>属性做变换，值是由 <code>Transform</code> API 生成的，上面链式调用就是确定其移动位置/旋转/缩放。</p>
<p>由于ART和svg的区别，如果需要从svg图转成ART代码，这个svg图最好全由path组成或者全部转成路径的写法。<br>这点其实很尴尬，也是开源社区出现上节提到的那个模块的主要原因。不过估计RN团队之后可能会做新的ART标签支持。</p>
<p>上面例子中的<code>generateSvgPath</code>是一个插值计算、返回路径字符串的一个函数，如果有现成的svg代码可以选择这么做，下面的例子则是利用ART的 <code>Path</code> API 构造一段路径，更有绘制的感觉。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 使用Path生成圆形</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">circlePathRender</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> path = Path().moveTo(<span class="number">0</span>,<span class="number">100</span>)</div><div class="line">    .arc(<span class="number">0</span>, radius * <span class="number">2</span>, radius)</div><div class="line">    .arc(<span class="number">0</span>, radius * <span class="number">-2</span>, radius)</div><div class="line">    .close(); <span class="comment">// 闭合路径</span></div><div class="line">  <span class="comment">// 构造而成的path可以直接复制给d属性</span></div><div class="line">  <span class="keyword">return</span> &lt;Shape d=&#123;path&#125; fill=&#123;'#2ba'&#125;/&gt;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 绘制多边形</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">polygonPathRender</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> path = Path().moveTo(<span class="number">10</span>, <span class="number">10</span>)</div><div class="line">    .lineTo(<span class="number">20</span>, <span class="number">30</span>)</div><div class="line">    .lineTo(<span class="number">30</span>, <span class="number">40</span>)</div><div class="line">    .lineTo(<span class="number">10</span>, <span class="number">60</span>)</div><div class="line">    .lineTo(<span class="number">0</span>, <span class="number">50</span>)</div><div class="line">    .lineTo(<span class="number">-20</span>, <span class="number">40</span>)</div><div class="line">    .close(); <span class="comment">// 闭合路径</span></div><div class="line">  <span class="keyword">return</span> &lt;Shape d=&#123;path&#125; fill=&#123;'#00a'&#125; stroke="yellow" strokeWidth=&#123;4&#125;/&gt;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>Path</code>的各种方法很接近svg标准，除了上面出现的<code>lineTo</code>/<code>moveTo</code>/<code>arc</code>之外，还有<code>arcTo</code>/<code>curve</code>/<code>line</code>等API<br>满足日常绘制需求。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 绘制文字</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">textRender</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> (</div><div class="line">    &lt;Text</div><div class="line">      font=&#123;`bold 13px "Helvetica Neue", "Helvetica", Arial`&#125;</div><div class="line">      fill="#749"</div><div class="line">      x=&#123;0&#125;</div><div class="line">      y=&#123;0&#125;</div><div class="line">    &gt;</div><div class="line">      Lorem ipsum dolor sit amet</div><div class="line">    &lt;/Text&gt;</div><div class="line">  );</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>上面的例子绘制文本，<code>font</code>属性可以选择使用对象<code>{fontWeight: &#39;bold&#39;, fontSize: 13, fontFamily: &#39;Helvetica,Neue Helvetica,Arial&#39;}</code>代替。</p>
<p>目前都使用一个固定的rgb值填充ART图像，<code>LinearGradient</code>和<code>RadialGradient</code>给我们像css一样用渐变色的选择。</p>
<ul>
<li>线性渐变</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// linearGradient 可赋值给Path或者Text标签的fill属性</span></div><div class="line"><span class="keyword">var</span> linearGradient = <span class="keyword">new</span> ART.LinearGradient(&#123;</div><div class="line">  <span class="string">"0"</span>: <span class="string">"#2ba"</span>,</div><div class="line">  <span class="string">".5"</span>: <span class="string">"#f90"</span>,</div><div class="line">  <span class="string">"0.7"</span>: <span class="string">"#aa4422"</span>,</div><div class="line">  <span class="string">"1"</span>: <span class="string">"rgba(255,255,255,0.5)"</span></div><div class="line">&#125;, <span class="number">0</span>, <span class="number">0</span>, <span class="number">100</span>, <span class="number">200</span>);</div></pre></td></tr></table></figure>
<p><code>LinearGradient</code>构造函数第一个参数是设定渐变色的对象，使用诸如<code>0.3</code>/<code>.52</code>/<code>1</code>这样的属性表示<code>30%</code>/<code>52%</code>/<code>100%</code>，值为颜色值，不符合要求的键值对会被忽略。<br>后面四个参数分别表示：起点x，起点y，终点x，终点y.</p>
<ul>
<li>径向渐变</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// radialGradient 可赋值给Path或者Text标签的fill属性</span></div><div class="line"><span class="keyword">var</span> radialGradient = <span class="keyword">new</span> ART.RadialGradient(&#123;</div><div class="line">  <span class="string">".1"</span>: <span class="string">"#2fb000"</span>,</div><div class="line">  <span class="string">".9"</span>: <span class="string">"#a080f0"</span>,</div><div class="line">&#125;, <span class="number">300</span>, <span class="number">200</span>, <span class="number">400</span>, <span class="number">400</span>, <span class="number">200</span>, <span class="number">200</span>);</div></pre></td></tr></table></figure>
<p><code>RadialGradient</code>构造函数第一个参数是和线性渐变相同的，后续六个分别表示：焦点x，焦点y，x半轴长，y半轴长，原点x，原点y.</p>
<h4 id="ART动画"><a href="#ART动画" class="headerlink" title="ART动画"></a>ART动画</h4><p>绘制矢量图标通过上述API的组合基本能实现，下面来讲讲动画效果的制作 (Kira☆~)</p>
<blockquote>
<p>首先感谢Jason Brown的ART动画分享~ 本节内容主要源自他的博文:<br><a href="http://browniefed.com/blog/react-native-morphing-svg-paths-with-react-art/" target="_blank" rel="external">art Morph动画</a><br><a href="http://browniefed.com/blog/react-native-how-to-create-twitter-exploding-hearts/" target="_blank" rel="external">art Animated动画</a></p>
</blockquote>
<p>第一个方法是使用ART它爷爷<code>art</code>库中的的<code>Morph</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 因为ART有art库的依赖，所以可以直接import</span></div><div class="line"><span class="keyword">import</span> Morph <span class="keyword">from</span> <span class="string">'art/morph/path'</span></div></pre></td></tr></table></figure>
<p>Morph的基本API是<code>Morph.Tween(startSvg, endSvg)</code>，指定了一个渐变的过程对象，该对象可以直接复制给<code>Shape</code>标签的<code>d</code>属性。</p>
<p>调用<code>Morph.Tween(startSvg, endSvg).tween(percentage)</code>可以指定其渐变的程度，从0到1.0的动画展示便是startSvg路径变换到endSvg路径的过程。</p>
<p>使用<code>requestAnimationFrame</code>修改保存在state中渐变对象的渐变程度可以方便地做出动画渐变的效果，具体可以看Jason Brown的<a href="(http://browniefed.com/blog/react-native-morphing-svg-paths-with-react-art/">博文</a>)。</p>
<hr>
<p>其实鉴于ART中无法使用RN其他标签这点，使用最老土的<code>state</code>绑定制作动画和<code>Animated</code>制作动画在笔者的测试中性能差别并不大。<br>因为ART在动画的过程中基本上整体都需要重绘，并不像一般RN标签做动画会牵扯到许多实际上无重绘需求的子节点。</p>
<p>不过<code>state</code>和动画样式耦合一般是不推荐的方式，且<code>Animated</code>提供的<code>sequence</code>/<code>parallel</code>/<code>spring</code>/<code>delay</code>/<code>event</code>等API为制作更复杂的动画提供了便利，所以更推荐大家使用<code>Animated</code>配合ART制作动画。</p>
<p>首先通过<code>Animated</code>为ART标签提供动画加持~</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> &#123;ART, Animated&#125; <span class="keyword">from</span> <span class="string">'react-native'</span>;</div><div class="line"><span class="keyword">const</span> &#123;Shape, Group&#125; = ART;</div><div class="line"><span class="keyword">const</span> AnimatedShape = Animated.createAnimatedComponent(Shape);</div><div class="line"><span class="keyword">const</span> AnimatedGroup = Animated.createAnimatedComponent(Group);</div></pre></td></tr></table></figure>
<p>可以让<code>AnimatedGroup</code>标签负责基于xy属性的移动动画</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 一颗星星的SVG代码</span></div><div class="line"><span class="keyword">const</span> STAR = <span class="string">'M 0.000 10.000 L 11.756 16.180 L 9.511 3.090 L 19.021 -6.180 L 5.878 -8.090 L 0.000 -20.000 L -5.878 -8.090 L -19.021 -6.180 L -9.511 3.090 L -11.756 16.180 L 0.000 10.000'</span></div><div class="line"></div><div class="line"><span class="comment">// 某组件中...</span></div><div class="line"><span class="keyword">constructor</span> (props) &#123;</div><div class="line">  <span class="keyword">super</span>(props);</div><div class="line">  <span class="keyword">this</span>.state = &#123;</div><div class="line">    <span class="comment">// 设定Animated.Value初值</span></div><div class="line">    value: <span class="keyword">new</span> Animated.Value(<span class="number">0</span>)</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">this</span>.infiniteAnimate = <span class="keyword">this</span>.infiniteAnimate.bind(<span class="keyword">this</span>);</div><div class="line">&#125;</div><div class="line">componentDidMount () &#123;</div><div class="line">  <span class="keyword">this</span>.infiniteAnimate();</div><div class="line">&#125;</div><div class="line"><span class="comment">// 无限循环动画</span></div><div class="line">infiniteAnimate () &#123;</div><div class="line">  Animated.timing(<span class="keyword">this</span>.state.value, &#123;</div><div class="line">    <span class="attr">duration</span>: <span class="number">1000</span>,</div><div class="line">    <span class="attr">toValue</span>: <span class="number">1</span></div><div class="line">  &#125;).start(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</div><div class="line">    Animated.timing(<span class="keyword">this</span>.state.value, &#123;</div><div class="line">      <span class="attr">duration</span>: <span class="number">2000</span>,</div><div class="line">      <span class="attr">toValue</span>: <span class="number">0</span></div><div class="line">    &#125;).start(<span class="keyword">this</span>.infiniteAnimate);</div><div class="line">  &#125;);</div><div class="line">&#125;</div><div class="line">render () &#123;</div><div class="line">  <span class="comment">// 不断缩小放大的星星</span></div><div class="line">  <span class="keyword">return</span> (</div><div class="line">    &lt;View&gt;</div><div class="line">      &lt;Surface width=&#123;width&#125; height=&#123;height&#125;&gt;</div><div class="line">        &lt;AnimatedShape</div><div class="line">          d=&#123;STAR&#125;</div><div class="line">          x=&#123;30&#125;</div><div class="line">          y=&#123;30&#125;</div><div class="line">          fill=&#123;"#280"&#125;</div><div class="line">          scale=&#123;this.state.value&#125;</div><div class="line">        /&gt;</div><div class="line">      &lt;/Surface&gt;</div><div class="line">    &lt;/View&gt;</div><div class="line">  );</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>做了这样一个demo：</p>
<p><img src="http://7xjgb0.com1.z0.glb.clouddn.com/artAnimationStars.gif" width="400"></p>
<p></p>

<p>具体的使用和<code>Animated.View</code>之类相同，更复杂的例子看<a href="http://browniefed.com/blog/react-native-animated-with-react-art-firework-show/" target="_blank" rel="external">这篇文章</a></p>
<h3 id="目前ART相关的项目"><a href="#目前ART相关的项目" class="headerlink" title="目前ART相关的项目"></a>目前ART相关的项目</h3><ul>
<li><a href="https://github.com/react-native-community/react-native-svg" target="_blank" rel="external">react-native-svg</a> 让ART支持所有svg标签</li>
<li><a href="https://github.com/matc4/react-native-svg-uri" target="_blank" rel="external">react-native-svg-uri</a> 依赖上面的<code>react-native-svg</code>让<code>&lt;Image&gt;</code>标签的source可使用svg的uri</li>
<li><a href="https://github.com/oblador/react-native-progress" target="_blank" rel="external">react-native-progress</a> ART做的进度条组件</li>
<li><a href="https://github.com/xgfe/react-native-grading" target="_blank" rel="external">react-native-grading</a> 笔者学习ART时做的一个评分组件</li>
</ul>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>React Native ART让RN开发者使用类svg语法绘制矢量图形，优点在于同步渲染/高清无码，并且可绘制简单的动画。<br>目前的坑在于未实现所有svg标签支持、安卓模拟器使用易奔溃、动画和绘制的开发效率不一定很高（相比于最近火爆酷炫的<a href="https://github.com/airbnb/lottie-react-native" target="_blank" rel="external">lottie</a>)<br>ART动画的性能在安卓真机上也堪忧，不过这更多的应该是RN平台的问题，相信日后会有所改善。</p>
<p>另外需要注意的是，ART不支持目前RN团队推荐的<code>jest</code> snapshot测试，还是老老实实用<code>enzyme</code>吧</p>
<p>不太建议在C端等用户体验要求较高的项目中使用ART动画（<del>不过C端有敢用RN的么</del>）</p>
<p>总而言之，ART其“画”UI的能力确实给了开发者很大的自定义空间。</p>
</span>
      
    </div>

    <footer class="post-footer">

      
        <div class="post-nav">
          <div class="post-nav-prev post-nav-item">
            
              <a href="/2017/02/08/zhiqin/Coordinators/" rel="prev">Coordinators探险——Fragment和ViewGroup的抉择</a>
            
          </div>

          <div class="post-nav-next post-nav-item">
            
              <a href="/2017/02/04/wangweitao/RxJava_Migration/" rel="next">The Next Step for Reactive Android Programming（译文）</a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
        <!-- JiaThis Button BEGIN -->
<div class="jiathis_style">
  <a class="jiathis_button_tsina"></a>
  <a class="jiathis_button_tqq"></a>
  <a class="jiathis_button_weixin"></a>
  <a class="jiathis_button_cqq"></a>
  <a class="jiathis_button_douban"></a>
  <a class="jiathis_button_renren"></a>
  <a class="jiathis_button_qzone"></a>
  <a class="jiathis_button_kaixin001"></a>
  <a class="jiathis_button_copy"></a>
  <a href="http://www.jiathis.com/share" class="jiathis jiathis_txt jiathis_separator jtico jtico_jiathis" target="_blank"></a>
  <a class="jiathis_counter_style"></a>
</div>
<script type="text/javascript" >
  var jiathis_config={
    hideMore:false
  }
</script>
<script type="text/javascript" src="http://v3.jiathis.com/code/jia.js" charset="utf-8"></script>
<!-- JiaThis Button END -->

      
    </div>
  </div>

 </div>

        

        
          <div class="comments" id="comments">
            <div id="SOHUCS" sid="" ></div>
          </div>
        
      </div>

      
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <a href="https://github.com/xgfe" target="_blank"><img class="site-author-image" src="http://p0.meituan.net/xgfe/082a9624ba5ae8602150a2d43968463e49348.png" alt="xgfe" itemprop="image"/></a>
          <p class="site-author-name" itemprop="name">xgfe</p>
        </div>
        <p class="site-description motion-element" itemprop="description">xgfe's blog. 鲜果前端的技术博客，鲜果前端研发部官方博客。前端基础技术研究：html, html5, javascript, css, css3；前端框架研究：angularJs, react, react native.</p>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">89</span>
              <span class="site-state-item-name">日志</span>
            </a>
          </div>

          <div class="site-state-item site-state-categories">
            
              <span class="site-state-item-count">37</span>
              <span class="site-state-item-name">作者</span>
              
          </div>

          <div class="site-state-item site-state-tags">
            <a href="/tags">
              <span class="site-state-item-count">131</span>
              <span class="site-state-item-name">标签</span>
              </a>
          </div>

        </nav>

        
          <div class="feed-link motion-element">
            <a href="/atom.xml" target="_blank" rel="alternate">
              <i class="menu-item-icon icon-next-feed"></i>
              RSS
            </a>
          </div>
        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/xgfe" target="_blank">GitHub</a>
              </span>
            
          
        </div>

        
        

        <div class="links-of-author motion-element">
          
        </div>

      </section>

      
        <section class="post-toc-wrap sidebar-panel-active">
          <div class="post-toc-indicator-top post-toc-indicator"></div>
          <div class="post-toc">
            
            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#React-Native-ART-由来"><span class="nav-number">1.</span> <span class="nav-text">React Native ART 由来</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ART能干什么"><span class="nav-number">2.</span> <span class="nav-text">ART能干什么</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#上手ART"><span class="nav-number">3.</span> <span class="nav-text">上手ART</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#事先准备"><span class="nav-number">3.1.</span> <span class="nav-text">事先准备</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#基本API"><span class="nav-number">3.2.</span> <span class="nav-text">基本API</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ART基础使用栗子"><span class="nav-number">3.3.</span> <span class="nav-text">ART基础使用栗子</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ART动画"><span class="nav-number">3.4.</span> <span class="nav-text">ART动画</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#目前ART相关的项目"><span class="nav-number">4.</span> <span class="nav-text">目前ART相关的项目</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#总结"><span class="nav-number">5.</span> <span class="nav-text">总结</span></a></li></ol></div>
            
          </div>
          <div class="post-toc-indicator-bottom post-toc-indicator"></div>
        </section>
      

    </div>
  </aside>


    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner"> <div class="copyright" >
  
  &copy; &nbsp; 
  <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="icon-next-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">xgfe</span>
</div>

<div class="powered-by">
  由 <a class="theme-link" target="_blank" href="http://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Mist
  </a>
</div>


 </div>
    </footer>

    <div class="back-to-top"></div>
  </div>

  <script type="text/javascript" src="/vendors/jquery/index.js?v=2.1.3"></script>

  
  
  
    <script type="text/javascript"> 
(function(){ 
var appid = 'cysWiXvkm'; 
var conf = 'prod_fc970dbe85103c7a79b2c4f3dc7fb190'; 
var width = window.innerWidth || document.documentElement.clientWidth; 
if (width < 960) { 
window.document.write('<script id="changyan_mobile_js" charset="utf-8" type="text/javascript" src="http://changyan.sohu.com/upload/mobile/wap-js/changyan_mobile.js?client_id=' + appid + '&conf=' + conf + '"><\/script>'); } else { var loadJs=function(d,a){var c=document.getElementsByTagName("head")[0]||document.head||document.documentElement;var b=document.createElement("script");b.setAttribute("type","text/javascript");b.setAttribute("charset","UTF-8");b.setAttribute("src",d);if(typeof a==="function"){if(window.attachEvent){b.onreadystatechange=function(){var e=b.readyState;if(e==="loaded"||e==="complete"){b.onreadystatechange=null;a()}}}else{b.onload=a}}c.appendChild(b)};loadJs("http://changyan.sohu.com/upload/changyan.js",function(){window.changyan.api.config({appid:appid,conf:conf})}); } })(); </script>
    

  


  
  
  <script type="text/javascript" src="/vendors/fancybox/source/jquery.fancybox.pack.js"></script>
  <script type="text/javascript" src="/js/fancy-box.js?v=0.4.5.1"></script>


  <script type="text/javascript" src="/js/helpers.js?v=0.4.5.1"></script>
  

  <script type="text/javascript" src="/vendors/velocity/velocity.min.js"></script>
  <script type="text/javascript" src="/vendors/velocity/velocity.ui.min.js"></script>

  <script type="text/javascript" src="/js/motion_global.js?v=0.4.5.1" id="motion.global"></script>




  <script type="text/javascript" src="/js/nav-toggle.js?v=0.4.5.1"></script>
  <script type="text/javascript" src="/vendors/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  
<script type="text/javascript" src="/js/bootstrap.scrollspy.js?v=0.4.5.1" id="bootstrap.scrollspy.custom"></script>


<script type="text/javascript" id="sidebar.toc.highlight">
  $(document).ready(function () {
    var tocSelector = '.post-toc';
    var $tocSelector = $(tocSelector);
    var activeCurrentSelector = '.active-current';

    $tocSelector
      .on('activate.bs.scrollspy', function () {
        var $currentActiveElement = $(tocSelector + ' .active').last();

        removeCurrentActiveClass();
        $currentActiveElement.addClass('active-current');

        $tocSelector[0].scrollTop = $currentActiveElement.position().top;
      })
      .on('clear.bs.scrollspy', function () {
        removeCurrentActiveClass();
      });

    function removeCurrentActiveClass () {
      $(tocSelector + ' ' + activeCurrentSelector)
        .removeClass(activeCurrentSelector.substring(1));
    }

    function processTOC () {
      getTOCMaxHeight();
      toggleTOCOverflowIndicators();
    }

    function getTOCMaxHeight () {
      var height = $('.sidebar').height() -
                   $tocSelector.position().top -
                   $('.post-toc-indicator-bottom').height();

      $tocSelector.css('height', height);

      return height;
    }

    function toggleTOCOverflowIndicators () {
      tocOverflowIndicator(
        '.post-toc-indicator-top',
        $tocSelector.scrollTop() > 0 ? 'show' : 'hide'
      );

      tocOverflowIndicator(
        '.post-toc-indicator-bottom',
        $tocSelector.scrollTop() >= $tocSelector.find('ol').height() - $tocSelector.height() ? 'hide' : 'show'
      )
    }

    $(document).on('sidebar.motion.complete', function () {
      processTOC();
    });

    $('body').scrollspy({ target: tocSelector });
    $(window).on('resize', function () {
      if ( $('.sidebar').hasClass('sidebar-active') ) {
        processTOC();
      }
    });

    onScroll($tocSelector);

    function onScroll (element) {
      element.on('mousewheel DOMMouseScroll', function (event) {
          var oe = event.originalEvent;
          var delta = oe.wheelDelta || -oe.detail;

          this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
          event.preventDefault();

          toggleTOCOverflowIndicators();
      });
    }

    function tocOverflowIndicator (indicator, action) {
      var $indicator = $(indicator);
      var opacity = action === 'show' ? 0.4 : 0;
      $indicator.velocity ?
        $indicator.velocity('stop').velocity({
          opacity: opacity
        }, { duration: 100 }) :
        $indicator.stop().animate({
          opacity: opacity
        }, 100);
    }

  });
</script>

<script type="text/javascript" id="sidebar.nav">
  $(document).ready(function () {
    var html = $('html');
    var TAB_ANIMATE_DURATION = 200;
    var hasVelocity = $.isFunction(html.velocity);

    $('.sidebar-nav li').on('click', function () {
      var item = $(this);
      var activeTabClassName = 'sidebar-nav-active';
      var activePanelClassName = 'sidebar-panel-active';
      if (item.hasClass(activeTabClassName)) {
        return;
      }

      var currentTarget = $('.' + activePanelClassName);
      var target = $('.' + item.data('target'));

      hasVelocity ?
        currentTarget.velocity('transition.slideUpOut', TAB_ANIMATE_DURATION, function () {
          target
            .velocity('stop')
            .velocity('transition.slideDownIn', TAB_ANIMATE_DURATION)
            .addClass(activePanelClassName);
        }) :
        currentTarget.animate({ opacity: 0 }, TAB_ANIMATE_DURATION, function () {
          currentTarget.hide();
          target
            .stop()
            .css({'opacity': 0, 'display': 'block'})
            .animate({ opacity: 1 }, TAB_ANIMATE_DURATION, function () {
              currentTarget.removeClass(activePanelClassName);
              target.addClass(activePanelClassName);
            });
        });

      item.siblings().removeClass(activeTabClassName);
      item.addClass(activeTabClassName);
    });

    $('.post-toc a').on('click', function (e) {
      e.preventDefault();
      var targetSelector = escapeSelector(this.getAttribute('href'));
      var offset = $(targetSelector).offset().top;
      hasVelocity ?
        html.velocity('stop').velocity('scroll', {
          offset: offset  + 'px',
          mobileHA: false
        }) :
        $('html, body').stop().animate({
          scrollTop: offset
        }, 500);
    });

    // Expand sidebar on post detail page by default, when post has a toc.
    var $tocContent = $('.post-toc-content');
    if (isDesktop() && CONFIG.sidebar === 'post') {
      if ($tocContent.length > 0 && $tocContent.html().trim().length > 0) {
        displaySidebar();
      }
    }
  });
</script>



  <script type="text/javascript">
    $(document).ready(function () {
      if (CONFIG.sidebar === 'always') {
        displaySidebar();
      }
      if (isMobile()) {
        FastClick.attach(document.body);
      }
    });
  </script>

  

  
  

  
  <script type="text/javascript" src="/js/lazyload.js"></script>
  <script type="text/javascript">
    $(function () {
      $("#posts").find('img').lazyload({
        placeholder: "/images/loading.gif",
        effect: "fadeIn"
      });
    });
  </script>

  <!-- google search, added by felix -->
  <script>
      $('#gg-form').on('submit', function(e) {
        var keyword = $.trim($(this).find('#gg-search-input').val());
        if (keyword) {
          location.href = 'https://www.google.com.hk/?gfe_rd=cr&ei=hXw8VpjtHuLC8AeSuIjQAg&gws_rd=ssl#safe=strict&q='+encodeURIComponent(keyword)+'+site:xgfe.github.io';
        }
        return false;
      });
  </script>
  <!-- baidu 站长自动推送 -->
  <script>
  (function(){
      var bp = document.createElement('script');
      bp.src = '//push.zhanzhang.baidu.com/push.js';
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
  })();
  </script>
</body>
</html>
